跳到主要内容

Redis Cluster 要怎么使用

部署模式

Redis 在部署时,可以采用多种方式部署,每种部署方式对应不同的可用级别。

单节点部署:只有一个节点提供服务,读写均在此节点,此节点宕机则数据全部丢失,直接影响业务。

master-slave 方式部署:两个节点组成 master-slave 模式,在 master 上写入,slave 上读取,读写分离提高访问性能,master 宕机后,需要手动把 slave 提升为 master,业务影响程度取决于手动提升 master 的延迟。

master-slave + 哨兵方式部署:master-slave 与上述相同,不同的是增加一组哨兵节点,用于实时检查 master 的健康状态,在 master 宕机后自动提升 slave 为新的 master,最大程度降低不可用的时间,对业务影响时间较短。

从上面几种部署模式可以看出,提高 Redis 可用性的关键是:多副本部署 + 自动故障恢复,而多副本正是依赖主从复制。

哨兵节点是什么?

Redis Sentinel(哨兵)是 Redis 的一个高可用性解决方案,用于监控和管理 Redis 主从复制架构中的故障恢复和故障转移。哨兵是一个独立的进程,可以监控多个 Redis 实例,并在主节点发生故障时自动将一个从节点升级为新的主节点。

哨兵的主要功能包括:

  1. 监控:哨兵定期检查 Redis 主节点和从节点的状态,确保它们正常工作。如果一个节点无法正常响应,哨兵会将其标记为下线状态。

  2. 故障检测和自动故障转移:当一个 Redis 主节点被标记为下线状态时,哨兵会进行故障检测,确认主节点是否真的不可用。如果确认主节点不可用,哨兵会选择一个健康的从节点,并将其升级为新的主节点。

  3. 配置提供和重配置:哨兵会监控 Redis 配置的变化,并在需要时将新的配置传播给 Redis 客户端。这样,客户端可以通过哨兵获取 Redis 服务的最新配置信息。

通过使用哨兵,可以提供 Redis 的高可用性,确保在主节点故障时自动进行故障转移,从而保证 Redis 服务的连续可用性。哨兵还可以自动监控并重新配置 Redis 的主从架构,适应变化的需求。

需要注意的是,Redis Sentinel 是一个独立的组件,需要单独部署和配置,而不是作为 Redis 本身的一部分。

如果不使用 Redis Sentinel

注意 Redis Sentinel 并不是必需的,可以选择不使用 Redis Sentinel 并手动进行主节点的选举,但这会增加管理和维护的复杂性。

在 Redis 的主从复制架构中,当主节点失效时,从节点不会自动选举为新的主节点。相反,它将继续作为从节点,并等待被管理员手动升级为主节点。

如果你不使用Redis Sentinel,你可以手动执行以下步骤来进行主节点选举:

  1. 检测主节点失效:监控主节点的状态,当检测到主节点不可用时,需要确认其真正的失效,可以通过检查主节点的健康状态、网络连接情况等来确定。

  2. 选择一个从节点作为新的主节点:从当前的从节点中选择一个健康的节点作为新的主节点。这可以通过手动配置或使用一些脚本或工具来实现。

  3. 更新应用配置:将应用程序或客户端的配置更新为连接到新的主节点。这包括更新主节点的主机名或IP地址和端口号等信息。

  4. 重新配置其他节点:更新其他从节点的配置,使它们成为新的主节点的从节点。

手动进行主节点选举需要更多的人工操作和干预,可能会导致一些延迟和不便。而 Redis Sentinel 可以自动监控和管理主节点的故障转移,能够更快地检测到主节点失效并自动选举新的主节点,减少了人工干预的需求,提高了系统的可用性和可靠性。因此,对于大规模的、需要高可用性的生产环境,推荐使用 Redis Sentinel 来简化主节点选举的管理。

部署例子:节点配置

Redis 集群一般由多个节点组成,节点数量至少为 6 个,才能保证组成完整高可用的集群。Redis集群节点规划如下:

建议为集群内所有节点统一目录,一般划分三个目录:conf、data、log,分别存放 配置、数据 和 日志 相关文件。

这里只需将 redis.conf 复制 6份到 conf 目录下,更改为 cluster 所需的配置。data下新建6个文件夹,分别对应6个节点(用节点名命名)。log下新建6个日志文件(也是用节点名命名)。

Go 使用 Redis Cluster

package redis_cluster

import (
"fmt"
"log"
"strconv"
"testing"
"time"

"github.com/go-redis/redis/v7"
)

var clusterClient *redis.ClusterClient

func init() {
log.SetFlags(log.Llongfile | log.Lshortfile)
// 连接redis集群
clusterClient = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{ // 填写master主机
"192.168.21.22:30001",
"192.168.21.22:30002",
"192.168.21.22:30003",
},
Password: "123456", // 设置密码
DialTimeout: 50 * time.Microsecond, // 设置连接超时
ReadTimeout: 50 * time.Microsecond, // 设置读取超时
WriteTimeout: 50 * time.Microsecond, // 设置写入超时
})
// 发送一个ping命令,测试是否通
s := clusterClient.Do("ping").String()
fmt.Println(s)
}

func TestConnByRedisCluster(t *testing.T) {
// 测试一个set功能
s := clusterClient.Set("name", "barry", time.Second*60).String()
fmt.Println(s)
}
func TestPipe(t *testing.T) {
// 测试管道发送多条命令.
pipe := clusterClient.Pipeline()
for i := 0; i < 10; i++ {
pipe.Set("go"+strconv.Itoa(i), strconv.Itoa(i), time.Second*300)
}
// 真正执行发送操作.
result, err := pipe.Exec()
if err != nil {
t.Error(err)
}
t.Log(result)
}

// 验证上面是否拿到数据
func TestGetKey(t *testing.T) {
for i := 0; i < 10; i++ {
ret := clusterClient.Get("go" + strconv.Itoa(i)).String()
fmt.Println(ret)
}
}

Reference